﻿using MyMVC.attr;
using MyMVC.mapper;
using MyUtils;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Web.Compilation;

namespace MyMVC
{
    public class ContextLoader
    {
        // 保存PageAction的字典
        private static Dictionary<string, ActionMapper> s_PageActionDict;
        private static List<Type> s_Interceptors;
        private static List<Type> s_AllField;
        private static List<Type> s_AllClass;
        private static Dictionary<Type, Type> s_AutoWired;

        public static void Startup()
        {
            if (s_PageActionDict == null)
                s_PageActionDict = new Dictionary<string, ActionMapper>();
            if (s_Interceptors == null)
                s_Interceptors = new List<Type>();
            if (s_AllField == null)
                s_AllField = new List<Type>();
            if (s_AllClass == null)
                s_AllClass = new List<Type>();
            if (s_AutoWired == null)
                s_AutoWired = new Dictionary<Type, Type>();
            ICollection assemblies = BuildManager.GetReferencedAssemblies();
            foreach (Assembly assembly in assemblies)
            {
                // 过滤以【System.】开头的程序集，加快速度
                if (assembly.FullName.Equals("System", StringComparison.OrdinalIgnoreCase)
                    || assembly.FullName.Equals("mscorlib", StringComparison.OrdinalIgnoreCase)
                    || assembly.FullName.StartsWith("System.", StringComparison.OrdinalIgnoreCase)
                    || assembly.FullName.StartsWith("Microsoft.", StringComparison.OrdinalIgnoreCase)
                    || assembly.FullName.StartsWith("DotNetOpenAuth.", StringComparison.OrdinalIgnoreCase))
                    continue;
                try
                {
                    foreach (Type t in assembly.GetExportedTypes())
                    {
                        if (t.IsSubclassOf(typeof(ActionSupport)))
                        {
                            getActionMapper(t);
                        }
                        else if (t.IsSubclassOf(typeof(AbstractActionInterceptor)))
                        {
                            s_Interceptors.Add(t);
                        }
                        else
                        {
                            if (!t.IsInterface)
                                s_AllClass.Add(t);
                        }
                    }
                }
                catch { }
            }
            foreach (Type t in s_AllClass)
            {
                foreach (Type i in s_AllField)
                {
                    if (i.IsAssignableFrom(t))
                    {
                        s_AutoWired.Add(i, t);
                        break;
                    }
                }
            }
            LogHelper.Info("started...  Actions => " + s_PageActionDict.Count);
        }

        private static void getActionMapper(Type t)
        {
            string package = "";
            object obj = getAttribute(t, typeof(PageUrl));
            if (obj != null)
            {
                package = ((PageUrl)obj).Url;
            }

            MethodInfo[] methods = t.GetMethods();
            if (methods != null && methods.Length > 0)
            {
                object obj2;
                string url;
                foreach (MethodInfo m in methods)
                {
                    obj2 = getAttribute2(m, typeof(PageUrl));
                    if (obj2 != null)
                    {
                        url = ((PageUrl)obj2).Url;
                        if (url.StartsWith("~"))
                            url = url.Substring(1);
                        else
                            url = package + url;
                        s_PageActionDict.Add(url, new ActionMapper(m, url, t));
                    }
                }
            }
            FieldInfo[] fields = t.GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
            if (fields != null && fields.Length > 0)
            {
                object obj2;
                foreach (FieldInfo f in fields)
                {
                    obj2 = getAttribute(f, typeof(AutoWired));
                    if (obj2 != null)
                    {
                        s_AllField.Add(f.FieldType);
                    }
                }
            }
        }

        private static object getAttribute(FieldInfo f, Type type)
        {
            object[] objs = f.GetCustomAttributes(type, false);
            if (objs != null && objs.Length > 0)
            {
                return objs[0];
            }
            return null;
        }

        private static object getAttribute2(MemberInfo m, Type type)
        {
            object[] objs = m.GetCustomAttributes(type, false);
            if (objs != null && objs.Length > 0)
            {
                return objs[0];
            }
            return null;
        }

        private static object getAttribute(Type t, Type type)
        {
            object[] objs = t.GetCustomAttributes(type, false);
            if (objs != null && objs.Length > 0)
            {
                return objs[0];
            }
            return null;
        }

        internal static ActionMapper getAction(string url)
        {
            if (s_PageActionDict.ContainsKey(url))
                return s_PageActionDict[url];
            return null;
        }

        internal static Dictionary<Type, Type> getAutoWired()
        {
            return s_AutoWired;
        }

        internal static List<Type> getInterceptors()
        {
            return s_Interceptors;
        }
    }
}
